﻿package org.deft.timer {

	import flash.display.Shape;
	import flash.events.Event;
	import flash.events.EventDispatcher;

	/**
	 * DStopWatch 实现多个计时器功能，默认只有一个,id为0；
	 * 如果需要多个，可以通过add方法添加，add时，会返回计时器id
	 * 如果想得到某一计时器，可通过id访问
	 */
	public class DStopWatch extends EventDispatcher {

		//可同时启动的最大计时器数目
		public static const ITEM_MAX:int = 50;

		private var newItemId:int = 0;

		/**
		 * 当前的所有计时器的数目
		 */
		private var items:Vector.<DWatchItem>;

		public function get itemTotalNum():int {
			return items.length;
		}

		public function getAllItems():Vector.<DWatchItem> {
			return items.concat();
		}
		/**
		 * 用于缓存
		 */
		private var wasteItems:Vector.<DWatchItem>;
		private var tickShape:Shape;

		/**
		 * DStopWatch创建时，会自动添加一个ID为0的WatchItem
		 *
		 */
		public function DStopWatch() {
			if (instance) {
				throw new Error("DStopWatch 单例已经存在");
			}
			instance = this;

			items = new Vector.<DWatchItem>();
			wasteItems = new Vector.<DWatchItem>();

			addItem(false);

			tickShape = new Shape();
		}

		public static function getInstance():DStopWatch {
			if (instance == null) {
				instance = new DStopWatch;
			}
			return instance;
		}

		private static var instance:DStopWatch = null;

		/**
		 * 添加一个 计时项
		 * @param play 是否立即运行
		 * @param needTime 需要计时的时间，单位为毫秒，默认值0，表示无限计时
		 * @return 添加成功返回WatchItem.id 否则返回-1
		 *
		 */
		public function addItem(play:Boolean = false, needMillisecond:Number = 0):DWatchItem {
			if (items.length >= ITEM_MAX) {
				return null;
			}
			var item:DWatchItem = buildItem(needMillisecond);

			if (play) {
				item.start();
				startTick();
			}
			return item;
		}

		private function buildItem(needMillisecond:Number = 0):DWatchItem {
			var item:DWatchItem;

			if (wasteItems.length > 0) {
				item = wasteItems.pop();
			} else {
				item = new DWatchItem(newItemId++, needMillisecond);
				item.addEventListener(DStopWatchEvent.START, startTick);
			}
			var leng:int = items.length;
			if (leng == 0) {
				items.push(item);
			} else {
				for (var i:int = leng - 1; i >= 0; i--) {
					var tempItem:DWatchItem = items[i];
					if (item.getID() > tempItem.getID()) {
						items.splice(i + 1, 0, item);
						break;
					}
				}
			}
			return item;
		}

		/**
		 * 移除指定id的计时器,不能移除默认ID为0的计时器
		 * @param id
		 * @return 成功返回被移除的WatchItem,不成功返回null
		 *
		 */
		public function removeItem(id:int):DWatchItem {
			if (id == 0) {
				throw new Error("ID 为0的计时器是默认的，不可被移除！");
			}
			var item:DWatchItem = null;
			var leng:int = items.length;
			var idx:int = getItemIndex(id);

			if (idx == -1) {
				return null;
			}
			item = items.splice(idx, 1)[0];
			wasteItems.push(item);
			return item;
		}

		private function getItemIndex(id:int):int {
			var low:int = 0;
			var high:int = items.length - 1;
			var mid:int;

			while (low <= high) {
				mid = (low + high) / 2;
				if (id == items[mid].getID()) {
					return mid;
				} else {
					if (id < items[mid].getID()) {
						high = mid - 1;
					} else {
						low = mid + 1;
					}
				}
			}
			//查找失败
			return -1;
		}

		public function startAll():void {
			for each (var item:DWatchItem in items) {
				item.start();
			}
			startTick();
		}

		public function pauseAll():void {
			for each (var item:DWatchItem in items) {
				item.pause();
			}
			stopTick();
		}

		public function stopAll():void {
			for each (var item:DWatchItem in items) {
				item.stop();
			}
			stopTick();
		}

		public function getItem(id:int = 0):DWatchItem {
			if (id == 0) {
				return items[0];
			}
			var idx:int = getItemIndex(id);
			if (idx == -1) {
				throw new Error("指定id为" + id + "的对象不存在");
			}
			return items[idx];
		}

		private function startTick(event:DStopWatchEvent = null):void {
			tickShape.addEventListener(Event.ENTER_FRAME, tickHandler);
		}

		private function stopTick():void {
			tickShape.removeEventListener(Event.ENTER_FRAME, tickHandler);
		}

		private function tickHandler(e:Event):void {
			var leng:int = items.length;
			var allStop:Boolean = true;
			var allPause:Boolean = true;
			var item:DWatchItem;
			for (var i:int = 0; i < leng; i++) {
				item = items[i];
				item.update();

				if (!item.getIsStoped()) {
					allStop = false;
				}
				if (!item.getIsPaused()) {
					allPause = false;
				}
			}
			dispatchEvent(new DStopWatchEvent(DStopWatchEvent.CHANGE));
			if (allStop || allPause) {
				stopTick();
				dispatchEvent(new DStopWatchEvent(DStopWatchEvent.ALL_OVER));
			}
		}

	}
}

